package com.mall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.mall.cart.dto.UserInfoDto;
import com.mall.cart.feign.ProductFeignClient;
import com.mall.cart.interceptor.CartIndexInterceptor;
import com.mall.cart.service.CartService;
import com.mall.cart.vo.CartItemVo;
import com.mall.cart.vo.CartVo;
import com.mall.common.constant.CartConstant;
import com.mall.common.dto.SkuInfoDTO;
import com.mall.common.utils.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: 谢君臣
 * @Date: 2022/8/8-15:46
 * @version: 1.0
 * @function:
 */
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;


    @Override
    public CartItemVo addToCart(Long skuId, int num) throws RuntimeException {
        BoundHashOperations<String, Object, Object> cartOptions = getCartOptions();
        String res = (String) cartOptions.get(skuId.toString());
        CartItemVo cartItemVo = new CartItemVo();
        if (StringUtils.isEmpty(res)) {
            try {
                CartItemVo finalCartItemVo = cartItemVo;
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    Result<SkuInfoDTO> result = productFeignClient.get(skuId);
                    SkuInfoDTO skuInfo = result.getData();
                    finalCartItemVo.setSkuId(skuId);
                    finalCartItemVo.setCount(num);
                    finalCartItemVo.setImg(skuInfo.getSkuDefaultImg());
                    finalCartItemVo.setCheck(true);
                    finalCartItemVo.setPrice(skuInfo.getPrice());
                    finalCartItemVo.setTitle(skuInfo.getSkuTitle());
                    finalCartItemVo.setTotalPrice();
                }, threadPoolExecutor);

                CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
                    Result<List<String>> listResult = productFeignClient.getAttrNameAndValue(skuId);
                    finalCartItemVo.setSkuAttr(listResult.getData());
                }, threadPoolExecutor);
                // 等待异步服务
                CompletableFuture.allOf(future, future1).get();
                cartOptions.put(skuId.toString(), JSON.toJSONString(cartItemVo));
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        } else {
            cartItemVo = JSON.parseObject(res, CartItemVo.class);
            cartItemVo.setCount(num+cartItemVo.getCount());
            cartItemVo.setTotalPrice();
            cartOptions.put(skuId.toString(),JSON.toJSONString(cartItemVo));
        }
        return cartItemVo;
    }

    @Override
    public CartItemVo getBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> options = getCartOptions();
        String res = (String) options.get(skuId.toString());
        return JSON.parseObject(res,CartItemVo.class);
    }

    @Override
    public CartVo getCart() {
        CartVo cartVo = new CartVo();
        UserInfoDto userInfoDto = CartIndexInterceptor.threadLocal.get();
        String key = "";
        String temp_key = CartConstant.CART_PREFIX + userInfoDto.getUserKey();
        // 临时购物车
        List<CartItemVo> tempCartItems = getCartItems(temp_key);
        if (userInfoDto.getUserId() != null) { // 用户已经登录
            // 合并临时购物车
            if (tempCartItems!=null&&tempCartItems.size()>0){
                tempCartItems.forEach(cartItemVo -> addToCart(cartItemVo.getSkuId(),cartItemVo.getCount()));
                // 清空临时购物车
                clearCart(temp_key);
            }
            key = CartConstant.CART_PREFIX + userInfoDto.getUserId();
            cartVo.setItems(getCartItems(key));

        }else
            cartVo.setItems(tempCartItems);
        return cartVo;
    }

    @Override
    public void clearCart(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public void checkCart(Integer isChecked, Long skuId) {
        CartItemVo cartItemVo = getBySkuId(skuId);
        cartItemVo.setCheck(isChecked == 1);
        BoundHashOperations<String, Object, Object> cartOptions = getCartOptions();
        cartOptions.put(skuId.toString(),JSON.toJSONString(cartItemVo));
    }

    @Override
    public void changeItemCount(Long skuId, int num) {
        CartItemVo cartItemVo = getBySkuId(skuId);
        cartItemVo.setCount(num);
        BoundHashOperations<String, Object, Object> cartOptions = getCartOptions();
        cartOptions.put(skuId.toString(),JSON.toJSONString(cartItemVo));
    }

    @Override
    public void deleteBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOptions = getCartOptions();
        cartOptions.delete(skuId.toString());
    }

    @Override
    public List<CartItemVo> getCurrentCartItems() {
        UserInfoDto userInfoDto = CartIndexInterceptor.threadLocal.get();
        if (userInfoDto==null)
            return null;
        else{
            List<CartItemVo> cartItems = getCartItems(CartConstant.CART_PREFIX + userInfoDto.getUserId());
            // 过滤选中的商品
            List<CartItemVo> collect = cartItems.stream().filter(CartItemVo::isCheck).collect(Collectors.toList());
            // 查询当前价格
            List<Long> skuIds = collect.stream().map(CartItemVo::getSkuId).collect(Collectors.toList());
            if (skuIds.size()==0)
                return null;
            Result<Map<String, BigDecimal>> result = productFeignClient.getPricesBySkuIds(skuIds);
            Map<String, BigDecimal> prices = result.getData();
            // todo 去掉下架商品
            List<CartItemVo> voList = collect.stream().map(item -> {
                item.setPrice(prices.get(item.getSkuId().toString()));
                return item;
            }).collect(Collectors.toList());
            return voList;
        }
    }

    private  List<CartItemVo> getCartItems(String key) {
        BoundHashOperations<String, Object, Object> cartOptions = redisTemplate.boundHashOps(key);
        List<Object> list = cartOptions.values();
        return list.stream().map(item -> {
            CartItemVo vo = JSON.parseObject(item.toString(), CartItemVo.class);
            return vo;
        }).collect(Collectors.toList());
    }

    private BoundHashOperations<String, Object, Object> getCartOptions() {
        UserInfoDto userInfoDto = CartIndexInterceptor.threadLocal.get();
        int time_out = 60*60*24*30;
        String key = "";
        if (userInfoDto.getUserId() != null) // 用户已经登录
            key = CartConstant.CART_PREFIX + userInfoDto.getUserId();
        else
            key = CartConstant.CART_PREFIX + userInfoDto.getUserKey();
        BoundHashOperations<String, Object, Object> boundHashOps = redisTemplate.boundHashOps(key);
        boundHashOps.expire(time_out,TimeUnit.SECONDS);
        return boundHashOps;
    }
}
